---
title: Shadcn Form
description: Learn how to integrate Emblor with shadcn/ui form.
---

In this guide, we will take a look at building forms with [shadcn/ui form component](https://ui.shadcn.com/docs/components/form) which uses [react-hook-form](https://react-hook-form.com/) and [zod](https://zod.dev).

<Tabs defaultValue="preview" className="relative mr-auto w-full">
  <div className="flex items-center justify-between pb-3">
    <TabsList className="w-full justify-start rounded-none border-b bg-transparent p-0">
      <TabsTrigger
        value="preview"
        className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
      >
        Preview
      </TabsTrigger>
      <TabsTrigger
        value="code"
        className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
      >
        Code
      </TabsTrigger>
    </TabsList>
  </div>
  <TabsContent value="preview" className="relative rounded-md border">
    <ShadcnFormDemo />
  </TabsContent>
  <TabsContent value="code">
    <div className="flex flex-col space-y-4">
      <div className="w-full rounded-md [&_pre]:my-0 [&_pre]:max-h-[350px] [&_pre]:overflow-auto">
      <CodeBlock value={`
    import { 
      Form, 
      FormControl, 
      FormDescription, 
      FormField, 
      FormItem, 
      FormLabel, 
      FormMessage 
    } from '@/components/ui/form';
    import { Button } from '@/components/ui/button';
    import { z } from 'zod';
    import { useForm } from 'react-hook-form';
    import { zodResolver } from '@hookform/resolvers/zod';
    import React from 'react';
    import { toast } from '@/components/ui/use-toast';
    import { Tag, TagInput } from 'emblor';

    const FormSchema = z.object({
      topics: z.array(
        z.object({
          id: z.string(),
          text: z.string(),
        }),
      ),
    });

    export default function Demo() {
      const form = useForm<z.infer<typeof FormSchema>>({
        resolver: zodResolver(FormSchema),
      });

      const [tags, setTags] = React.useState<Tag[]>([]);
      const [activeTagIndex, setActiveTagIndex] = React.useState<number | null>(null);

      const { setValue } = form;

      function onSubmit(data: z.infer<typeof FormSchema>) {
        toast({
          title: 'You submitted the following values:',
          description: (
            <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
              <code className="text-white">{JSON.stringify(data, null, 2)}</code>
            </pre>
          ),
        });
      }

      return (
        <section className="z-10 w-full flex flex-col items-center text-center gap-5">
          <div id="try" className="w-full py-8">
            <div className="w-full relative my-4 flex flex-col space-y-2">
              <div className="preview flex min-h-[350px] w-full justify-center p-10 items-center mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative rounded-md border">
                <Form {...form}>
                  <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 flex flex-col items-start">
                    <FormField
                      control={form.control}
                      name="topics"
                      render={({ field }) => (
                        <FormItem className="flex flex-col items-start">
                          <FormLabel className="text-left">Topics</FormLabel>
                          <FormControl className="w-full">
                            <TagInput
                              {...field}
                              placeholder="Enter a topic"
                              tags={tags}
                              className="sm:min-w-[450px]"
                              setTags={(newTags) => {
                                setTags(newTags);
                                setValue('topics', newTags as [Tag, ...Tag[]]);
                              }}
                               activeTagIndex={activeTagIndex}
                              setActiveTagIndex={setActiveTagIndex}
                            />
                          </FormControl>
                          <FormDescription className="text-left">
                          These are the topics that you&apos;re interested in.
                          </FormDescription>
                          <FormMessage />
                        </FormItem>
                      )}
                    />
                    <Button type="submit">Submit</Button>
                  </form>
                </Form>
              </div>
            </div>
          </div>
        </section>
      );
    }

`}/>

</div>
</div>

  </TabsContent>
</Tabs>

## Anatomy

<br />
```tsx
<Form>
  <FormField
    control={...}
    name="..."
    render={() => (
      <FormItem>
        <FormLabel />
        <FormControl>
          { /* tag input goes here */}
        </FormControl>
        <FormDescription />
        <FormMessage />
      </FormItem>
    )}
  />
</Form>
```

## Installation

<Steps>

### Installation

Install the **Form** component by running the following command:

<br />

```bash
npx shadcn-ui@latest add form
```

Install **Emblor** by running the following command:

<br />

```bash
npm install emblor
# Or, use any package manager of your choice.
```

### Create a form schema

Define the shape of your form using a Zod schema. You can read more about using Zod in the [Zod documentation](https://zod.dev).

```tsx showLineNumbers {3,5-7}
'use client';

import { z } from 'zod';

const FormSchema = z.object({
  topics: z.array(
    z.object({
      id: z.string(),
      text: z.string(),
    }),
  ),
});
```

### Define a form

Use the **useForm** hook from **react-hook-form** to create a form.

<br />

```tsx showLineNumbers {3-4,14-20,22-27}
'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';

const FormSchema = z.object({
  topics: z.array(
    z.object({
      id: z.string(),
      text: z.string(),
    }),
  ),
});

export function Form() {
  // 1. Define your form.
  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      topics: [],
    },
  });

  // 2. Define a submit handler.
  function onSubmit(data: z.infer<typeof FormSchema>) {
    toast({
      title: 'You submitted the following values:',
      description: (
        <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
          <code className="text-white">{JSON.stringify(data, null, 2)}</code>
        </pre>
      ),
    });
  }
}
```

Since **FormField** is using a controlled component, you need to provide a default value for the field. See the [React Hook Form docs](https://react-hook-form.com/docs/usecontroller) to learn more about controlled components.

### Build your form

We can now use the **Form** components to build our form.

<br />

```tsx showLineNumbers {7-17,28-50}
'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';

import { Button } from '@/components/ui/button';
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Tag, TagInput } from 'emblor';

const FormSchema = z.object({
  topics: z.array(
    z.object({
      id: z.string(),
      text: z.string(),
    }),
  ),
});

export function Form() {
  // ...

  const [tags, setTags] = React.useState<Tag[]>([]);

  const { setValue } = form;

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 flex flex-col items-start">
        <FormField
          control={form.control}
          name="topics"
          render={({ field }) => (
            <FormItem className="flex flex-col items-start">
              <FormLabel className="text-left">Topics</FormLabel>
              <FormControl className="w-full">
                <TagInput
                  {...field}
                  placeholder="Enter a topic"
                  tags={tags}
                  className="sm:min-w-[450px]"
                  setTags={(newTags) => {
                    setTags(newTags);
                    setValue('topics', newTags as [Tag, ...Tag[]]);
                  }}
                />
              </FormControl>
              <FormDescription className="text-left">
                These are the topics that you&apos;re interested in.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </Form>
  );
}
```

### Done

That's it. You now have a fully accessible form that is type-safe with client-side validation.

</Steps>
